#pragma once


#include "Timestamp.h"
#include "noncopyable.h"


#include <functional>
#include <memory>


class EventLoop;

/*
 * Channel里面封装了sockfd和感兴趣的event, 比如 EPOLLIN、EPOLLOUT事件, 同时还绑定了poller返回的具体事件
 **/
class Channel : noncopyable
{
public:
    using EventCallback = std::function<void()>;
    using ReadEventCallback = std::function<void(Timestamp)>;

    Channel(EventLoop* loop, int fd);
    ~Channel() = default;

    // fd得到poller通知之后，就进行对应事件的回调处理
    void handleEvent(Timestamp receiveTime);

    // 设置不同事件的回调函数
    void setReadCallback(ReadEventCallback cb) { m_readCallback = std::move(cb); }
    void setWriteCallback(EventCallback cb) { m_writeCallback = std::move(cb); }
    void setCloseCallback(EventCallback cb) { m_closeCallback = std::move(cb);}
    void setErrorCallback(EventCallback cb) { m_errorCallback = std::move(cb); }

    // 防止Chanenel被手动remove后，Channel还在执行对应的回调操作
    void tie(const std::shared_ptr<void>&);

    int getFd() const { return m_fd; }
    int getEvents() const { return m_events; }
    void setRevents(int revt) { m_revents = revt; }

    // 设置fd对应事件的状态
    void enableReading() { m_events |= kReadEvent; update(); }
    void disableReading() { m_events &= ~kReadEvent; update(); }
    void enableWriting() { m_events |= kWriteEvent; update(); }
    void disableWriting() { m_events &= ~kWriteEvent; update(); }
    void disableAll() { m_events = kNoneEvent; update(); }

    // 返回fd当前事件的状态
    bool isNoneEvent() const { return m_events == kNoneEvent; }
    bool isWriting() const { return m_events & kWriteEvent; }
    bool isReading() const { return m_events & kReadEvent; }

    int getIndex() { return m_index; }
    void setIndex(int idx) { m_index = idx; }

    EventLoop* ownerLoop() { return m_loop; }
    void remove();

private:
    // 更新事件
    void update();
    // 根据poller通知Channel发生的具体事件，进行具体的回调操作
    void handleEventWithGuard(Timestamp receiveTime);

private:
    static const int kNoneEvent;    // fd无感兴趣的事件的表示
    static const int kReadEvent;    // 读事件标识
    static const int kWriteEvent;   // 写事件标识

    EventLoop* m_loop;  // 事件循环
    const int m_fd;     // Pollerr监听的对象
    int m_events;       // 注册fd感兴趣的事件
    int m_revents;      // poller会返回具体发生的事件
    int m_index;        // 在EPollPoller中对应3种事件的状态(kNew kDelete kAdded)

    std::weak_ptr<void> m_tie; // 防止手动调用removeChnannel之后，还在使用channel对象（跨线程对象生命周期生成状态的验证）
    bool m_tied;

    // Channel能够获知fd最终发生的具体事件revents, 它就可以负责调用根据revents调用对应事件的回调
    ReadEventCallback m_readCallback;
    EventCallback m_writeCallback;
    EventCallback m_closeCallback;
    EventCallback m_errorCallback;
};